{
 "cells":[
  {
   "cell_type":"markdown",
   "source":[
    "# Libraries API Guide\n",
    "[Documentation](https:\/\/github.com\/Kotlin\/kotlin-jupyter\/blob\/master\/docs\/libraries.md)"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"yvyRyH288A7MoqtYzoauPM",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"0ON8yI917hwj8FeK0pQsky"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.kernelVersion"
   ],
   "execution_count":1,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "0.11.0.365"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"473vDoAud72LeO1mGYfdT5",
     "type":"CODE",
     "hide_input_from_viewers":true,
     "hide_output_from_viewers":true
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Dependencies and imports\n",
    "\n",
    "Assume we want to add binary dependency on some library.\n",
    "In this case let's add JAR coordinates of this library to the `dependencies`\n",
    "array of our descriptor. If it is not on Maven Central, we add repository\n",
    "(or repositories) where this dependency is located. Also, we can add\n",
    "default imports"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"3EWan5WOD4obPRmJJoHRyl",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"vS92wiTvpFntHSEMCrr5H9"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val dollar = \"$\"\n",
    "loadLibraryDescriptor(\n",
    "    \"\"\"\n",
    "    {\n",
    "        \"dependencies\": [\n",
    "            \"org.ileasile:kformat:${dollar}libVersion\"\n",
    "        ],\n",
    "        \"repositories\": [\n",
    "            \"https:\/\/maven.pkg.github.com\/ileasile\/kformat\"\n",
    "        ],\n",
    "        \"imports\": [\n",
    "            \"org.ileasile.kformat.*\"\n",
    "        ],\n",
    "        \"properties\": {\n",
    "            \"libVersion\": \"0.0.1\"\n",
    "        }\n",
    "    }\n",
    "    \"\"\",\n",
    "    mapOf(\"libVersion\" to \"0.0.2\")\n",
    ")"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"0CWJquaSDtgDzeUv0DimCZ",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"3XSS7u0TNIQpjxsTLZoRig"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "Huh, we've got 401(Unauthorized). That's because reading from GitHub Packages\n",
    "requires authorization. We can add authorization for our repository in descriptor."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"V4uuN3nNDZXE311jEAydWG",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"9aQzeJN8aSKkrM8z1a8Acs"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val readToken = \"ghp_<your read token>\""
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"6yN7sFRwduz7klnJgPrB7X",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"XiD8FUF2KgFyi8XBVKQpnU"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "loadLibraryDescriptor(\"\"\"\n",
    "    {\n",
    "        \"dependencies\": [\n",
    "            \"org.ileasile:kformat:0.0.2\"\n",
    "        ],\n",
    "        \"repositories\": [\n",
    "            {\n",
    "                \"path\": \"https:\/\/maven.pkg.github.com\/ileasile\/kformat\",\n",
    "                \"username\": \"ileasile\",\n",
    "                \"password\": \"$readToken\"\n",
    "            }\n",
    "        ],\n",
    "        \"imports\": [\n",
    "            \"org.ileasile.kformat.*\"\n",
    "        ]\n",
    "    }\n",
    "\"\"\")"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"ICuKkECCy5fwEPqwa2R1CX",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"guaD3yArd3wnoMlMhxLe4X"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "kFormat {\n",
    "    color(BasicColor.Red) {\n",
    "        italic {\n",
    "            + \"Red italic text\"\n",
    "        }\n",
    "    }\n",
    "}.asAnsiEscaped()"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "\u001b[31m\u001b[3mRed italic text\u001b[m\u001b[31m\u001b[m\u001b[m"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"3Mn7l2KWXSxKCw6uMPijdM",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"iUfleWm1l7UrnMboME6qdN"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "Another way to do the same thing using Kotlin API:"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"Yaijjy4T9JqYtAASLGAqul",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"SZQ4DmXm4LKPZXSWKa2FUa"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    dependencies(\"org.ileasile:kformat:0.0.2\")\n",
    "    repository(\n",
    "        \"https:\/\/maven.pkg.github.com\/ileasile\/kformat\",\n",
    "        \"ileasile\",\n",
    "        readToken\n",
    "    )\n",
    "    import(\"org.ileasile.kformat.*\")\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"XcH81I9hFMNzCHqxiMEJUE",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"SqdpEchM5GWiblQZFplRpl"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "Also, Kotlin API allows to define dependencies in Gradle style:"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"staCddVMHTi49I5b31E1tk",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"YrLfbBZxK3gmzAjhOcToTI"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    dependencies {\n",
    "        implementation(\"org.ileasile:kformat:0.0.2\")\n",
    "    }\n",
    "    repositories {\n",
    "        maven {\n",
    "            url = \"https:\/\/maven.pkg.github.com\/ileasile\/kformat\"\n",
    "            credentials {\n",
    "                username = \"ileasile\"\n",
    "                password = readToken\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "    import(\"org.ileasile.kformat.*\")\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"CFm4qEKjHsxHHGyVltuetk",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"aY56fUvdq8nKDNJRhibmjc"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "\/\/@file:DependsOn\n",
    "\/\/@file:Repository"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"pvtJ9O84yMmtOfFEvlXXc0",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"cM7Eec2U1CVBlHSH17Rg1D"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Initialization callbacks\n",
    "You can define the code that should be run after library initialization.\n",
    "In descriptors, only code executions are available for this purpose.\n",
    "In Kotlin API you can do a bit more."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"2t4kFtppYUB60JpAX4G0Vy",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"c3ukpEDkef9NnK5W6m80fX"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "loadLibraryDescriptor(\"\"\"\n",
    "    {\n",
    "        \"init\": [\n",
    "            \"val myVar1 = 42\",\n",
    "            \"fun doInit1() {}\",\n",
    "            \"println(\\\"Library 1 initialized\\\")\"\n",
    "        ]\n",
    "    }\n",
    "\"\"\")"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "Library 1 initialized\r\n"
     ],
     "output_type":"stream"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"L1LDqh7lkS1goN8rbBjSIE",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"bJriUMfF1ALMgCZRqL2vPR"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "class Config(\n",
    "    var bufferSize: Int = 100\n",
    ")\n",
    "\n",
    "val config1 = Config()\n",
    "\n",
    "USE {\n",
    "    onLoaded {\n",
    "        declare(\"myVar3\" to config1)\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"9eqic9jFlk5HV7wtGa0xxV",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"eg2gxPucspll8gUsgPMeml"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "myVar3.bufferSize = myVar1"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"jiSOTAXlmYqOJp0PhnBgnT",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"WOxFiL3cGnwp0EfdM7ZMHv"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "myVar3.bufferSize"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "42"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"4ZHpp8jFXYZuKXCBbchbFV",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"PwhJpKfF01V5FgWZ0vKmJH"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "myVar3.bufferSize = 10"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"oE4AsSeJFz2ekobazrAZyL",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"ajiBPydxHG4Xeq9tlTUVNm"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "config1.bufferSize"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "10"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"I19AnHiRpO5KqIFPSgZ4tW",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"trd9FQC5p4kj2twt1NSdZi"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Before- and after-cell callbacks\n",
    "\n",
    "Sometimes you may want to execute some code before cell execution.\n",
    "That's how you can achieve it with library descriptor"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"t2yRsMNARg8l0sorhYSM2s",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"ytCzH78nG3CehElCoOlCp2"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "loadLibraryDescriptor(\"\"\"\n",
    "    {\n",
    "        \"initCell\": [\n",
    "            \"println(\\\"Before cell execution - 1\\\")\"\n",
    "        ]\n",
    "    }\n",
    "\"\"\")"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"BIsRgylmv6Ck8pCagHjIfQ",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"kIehA33S1UmxSoILQBOezz"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "2 + 2 + 7"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "Before cell execution - 1\r\n",
      "\n"
     ],
     "output_type":"stream"
    },
    {
     "name":"stderr",
     "text":[
      "\n"
     ],
     "output_type":"stream"
    },
    {
     "data":{
      "text\/plain":[
       "11"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"AzGRGqzpPJipHpBnXJmFzs",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"loTaywakOhZgSG9nNxroBD"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "You can achieve the same thing using Kotlin API"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"eARU2WTPp6GXOG3A2eatMP",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"aRiAfUct8tkDWLUoCXSPUa"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    beforeCellExecution {\n",
    "        println(\"Before cell execution - 2\")\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "Before cell execution - 1\r\n"
     ],
     "output_type":"stream"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"1sxa0CXvhLZDzOhrskiMbO",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"29gNY5AfVcwwJIu9XdIeZC"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "2 + 2"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "Before cell execution - 1\r\n",
      "Before cell execution - 2\r\n",
      "\n"
     ],
     "output_type":"stream"
    },
    {
     "name":"stderr",
     "text":[
      "\n"
     ],
     "output_type":"stream"
    },
    {
     "data":{
      "text\/plain":[
       "4"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"q0Aua9OEl1Z2vV3jqDgf1d",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"qPr8FSa9A021OrxQcpqgvf"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "You can manage added callbacks. Let's clear them."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"1m5WHFHEZTkENJegwK28fp",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"5H8VGC7gJEfYKSDQ1wDrFw"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.beforeCellExecutionsProcessor.unregisterAll()"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "Before cell execution - 1\r\n",
      "Before cell execution - 2\r\n"
     ],
     "output_type":"stream"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"QOda8P2ggk7v4KPAXRBBSH",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"LEj97CaHd6FEIUoWTDWrUd"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "2 + 2"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "4"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"1AhY64SK9ZxwRYARDBoZBL",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"kUqpFEoT4wdrCyvaRjlL9U"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "With Kotlin API, you can also create callbacks that are run after cells execution. Execution result is passed to them."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"ZbulAcAi9qUoHNTvuIiBlv",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"83T4EixM904negk4PspoX9"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    afterCellExecution { snippetInstance, result ->\n",
    "        val maybeDoubledResult = (result.value as? Int)?.let { it * 2 }\n",
    "        println(\"After execution of $snippetInstance: $maybeDoubledResult (${result.name})\")\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"1byxvh0xyBADy8SwMLniCS",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"jiBee7WXAMh0dRE0mXCwYJ"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "2 + 2"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "After execution of Line_34_jupyter@4306c59c: 8 (res34)\r\n",
      "\n"
     ],
     "output_type":"stream"
    },
    {
     "name":"stderr",
     "text":[
      "\n"
     ],
     "output_type":"stream"
    },
    {
     "data":{
      "text\/plain":[
       "4"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"noRPMGssyqDY0I3ylUbUyF",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"vWW1rKGiTC5wCiRppqSPtl"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "Let's remove this callback as well, but do it in a bit more complicated manner"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"ZsKekEpBlqek77sWCjZNyw",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"NZYYw8krWxxsn6ViFn8HQZ"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.afterCellExecutionsProcessor.let { processor ->\n",
    "    processor.unregister(processor.registeredExtensions().first())\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"v3NZFJcHzeAbSs7N7RFbGH",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"dr2BNXz8zjk4Heei7SHzTo"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Shutdown and interruption callbacks\n",
    "\n",
    "Kernel users have the ability to interrupt, restart and stop the kernel.\n",
    "What does it mean?\n",
    "\n",
    "**Interruption** just interrupts current cell execution. For example,\n",
    "if the user has run very long or infinite computation, they might want\n",
    "to interrupt it. After interruption kernel state remains untouched.\n",
    "\n",
    "**Stopping** kernel means just stopping the session. Kernel process is aborted,\n",
    "kernel state is aborted too.\n",
    "\n",
    "**Restarting** kernel means stopping followed by starting. Kernel process\n",
    "is aborted and then started again, kernel state is also cleared.\n",
    "\n",
    "Sometimes you may want to write a callback on kernel interruption or shutdown (that happens on stopping or restarting). And you can, using descriptor or Kotlin API."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"pzpQRXUrmoe70HgLdNw7vd",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"HLOTmBX4YcaBXoCInGaWBA"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "\/\/ Interruption callbacks aren't supported by descriptor API\n",
    "loadLibraryDescriptor(\"\"\"\n",
    "    {\n",
    "        \"shutdown\": [\n",
    "            \"println(\\\"Bye!\\\")\"\n",
    "        ]\n",
    "    }\n",
    "\"\"\")"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"7CKOXDY3J8daQDdptDqR77",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"sZDxeSOclpqLQU6I3U4ZFU"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "var interruptionCount = 0\n",
    "USE {\n",
    "    onShutdown {\n",
    "        println(\"Bye! (2)\")\n",
    "    }\n",
    "\n",
    "    onInterrupt {\n",
    "        ++interruptionCount\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"mMZepUVoYIFK0dFv0vrDT5",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"XJdz2W54VQ71MD37E7zK44"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "while(true) {}"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stderr",
     "text":[
      "The execution was interrupted"
     ],
     "output_type":"stream"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"wDfX0A3EqhWkX2UCADHWvM",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"sWNQSLVUcaeEBmAPpke16g"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "Shutdown callbacks can be managed by corresponding processor.\n",
    "API for extensions management will be most likely reworked in the future\n",
    "versions of kernel."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"LDvkJAbLhf0sLT8naKOpdj",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"9uUmhY5IEWb0F9Z4LLL9ns"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "interruptionCount"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "1"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"AxHz6sT8igD0xHatR2O3TI",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"9aUzTpm3Fs3zjX6Fl5svDH"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.shutdownExecutionsProcessor.unregisterAll()\n",
    "notebook.interruptionCallbacksProcessor.unregisterAll()"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"jVo4UAFNdHBeHnI0NgQTEy",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"XKeLbzujSGyt7sGXweJGW6"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Color scheme change callbacks\n",
    "\n",
    "Sometimes you may want to do something when the user changes current\n",
    "color scheme in their client. For example, you might want to change color\n",
    "scheme for newly created outputs or even update already created ones.\n",
    "You definitely can, but only in Kotlin API, and only if the user uses Kotlin Notebook plugin"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"Y8m8UCdfIZajEZZOo0DeSR",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"TjL2Gby4DlurAmXZNsOMiY"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "var isDark = notebook.currentColorScheme == ColorScheme.DARK\n",
    "USE {\n",
    "    println(\"Dark? - $isDark\")\n",
    "\n",
    "    onColorSchemeChange { colorScheme ->\n",
    "        isDark = colorScheme == ColorScheme.DARK\n",
    "        println(\"Color scheme is changed\")\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "Dark? - false\r\n",
      "Color scheme is changed\r\n"
     ],
     "output_type":"stream"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"kfACAahonfgtU9aTCjq8A5",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"FSrS8i1Hfq5tw0NeYR13tC"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "isDark"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "false"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"fPAAWxuXezIC0ijB7Z665a",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"wCZCvAr5I4GqhHJUWcEKSL"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.colorSchemeChangeCallbacksProcessor.unregisterAll()"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"2I7qSrr5q1pjDGlafkAkQb",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"8RvJheV7qmMV3TgAjrClo9"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Rendering"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"CShwMC7nRK99DulXh8qLcf",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"cZG2Gg1q6ricyrJ2obqEVN"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "Imagine you're developing a model for TicTacToe game and want to experiment with it in the notebook.\n",
    "You want to have some visual representation of the model. Now all what you have is a following\n",
    "string representation of the game state:"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"dcpELDBqZXULEmSZWx0H5S",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"MgHGwgpl2ke1SqG0BvCeuI"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val gameState = \"x_o|_x_|___\"\n",
    "gameState"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "x_o|_x_|___"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"y63yo6tLdvnMsm0KGSGdnu",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"CKP7bVtnKhgS7hYqLrbKIs"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "First thing you might want to do is to create a matrix containing the state in easier-to-use form"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"xGjOhoO7Z8zpMX2BUfFPy6",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"FYVprXZJX8ybIkUdRYlbMC"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "enum class TTTCell {\n",
    "    X, O, Empty\n",
    "}\n",
    "\n",
    "fun getGameState(state: String) = state.split('|')\n",
    "    .map { line ->\n",
    "        line.map {\n",
    "            when (it) {\n",
    "                'x' -> TTTCell.X\n",
    "                'o' -> TTTCell.O\n",
    "                '_' -> TTTCell.Empty\n",
    "                else -> error(\"Not possible\")\n",
    "            }\n",
    "        }\n",
    "    }"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"qzbgFqmprSHGn4hbFD4DeE",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"3CkWbCch8Jhw0YWvzybrWe"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val stateMatrix = getGameState(gameState)\n",
    "stateMatrix"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "[[X, Empty, O], [Empty, X, Empty], [Empty, Empty, Empty]]"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"pIEgOcSU0NZ7T2iMeis8jN",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"yO7NShs20PgUXH62mQECW9"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "class TTTState(val stateMatrix: List<List<TTTCell>>)"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"tGc4r1UI8QshX6E0SNwHlF",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"ueDFLSiaxErv3sQNrMRxQK"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val state = TTTState(stateMatrix)"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"lgYCIs3FwBLQgbbFcsvMvX",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"Zfx5UVcbiQybfkOTQunf2u"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "To render it, we may add a text renderer. Text renderers are supported only by Kotlin API and can only\n",
    "render values to string. Their benefit is that they can easily stack together: string are addable."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"JlMwa1IOmmwF53KAeZoY6n",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"mEXNvt604KWPfHBDZf3wLy"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    addTextRenderer(TextRenderer { _, value ->\n",
    "        (value as? TTTState)?.let { state ->\n",
    "            state.stateMatrix.joinToString(\"\\n\") { line ->\n",
    "                line.joinToString(\" \") {\n",
    "                    when (it) {\n",
    "                        TTTCell.X -> \"X\"\n",
    "                        TTTCell.O -> \"O\"\n",
    "                        TTTCell.Empty -> \"_\"\n",
    "                    }\n",
    "                }\n",
    "            }\n",
    "        }\n",
    "    })\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"KvqdiHpdZi2CphIYSxMj1r",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"uP4CXk9t9NAos3ns4xyVrl"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "state"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "X _ O\n",
       "_ X _\n",
       "_ _ _"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"z3IzOGeflKEYFIWPTw7hU8",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"XsGdpQCPHSyqtXVbcGgYN4"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "It's much better now, but we still might wish some graphic representation of the state.\n",
    "Let's create a couple of renderers. Renderers accept some values and return some other\n",
    "values. Rendering logic is described in [kernel documentation](https:\/\/github.com\/Kotlin\/kotlin-jupyter\/blob\/master\/docs\/README.md#rendering). Here, we register created renderers with `RenderersProcessor` and specify priority for them to ensure the order of  probation"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"rJECecwjQvVYlV4SIPIZc8",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"pHiR3R2hbskzidNu8lLsT0"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val htmlStateRenderer = createRenderer<TTTState> {\n",
    "    val style = \"\"\"\n",
    "        border: 1px solid black;border-collapse: collapse;\n",
    "    \"\"\".trimIndent()\n",
    "    val html =\n",
    "        it.stateMatrix.joinToString(\"\\n\", prefix = \"<div><table style='$style'>\", postfix = \"<\/table><\/div>\") { line ->\n",
    "            line.joinToString(\"\", prefix = \"<tr style='$style'>\", postfix = \"<\/tr>\") { cell ->\n",
    "                buildString {\n",
    "                    append(\"<td style='$style'>\")\n",
    "                    append(\n",
    "                        when (cell) {\n",
    "                            TTTCell.X -> \"X\"\n",
    "                            TTTCell.O -> \"O\"\n",
    "                            TTTCell.Empty -> \"\\u200D\"\n",
    "                        }\n",
    "                    )\n",
    "                    append(\"<\/td>\")\n",
    "                }\n",
    "            }\n",
    "        }\n",
    "    mimeResult(\n",
    "        MimeTypes.HTML to html,\n",
    "        MimeTypes.PLAIN_TEXT to it.stateMatrix.toString()\n",
    "    )\n",
    "}\n",
    "notebook.renderersProcessor.registerWithoutOptimizing(htmlStateRenderer, ProcessingPriority.DEFAULT + 5)"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"DLTsEANu9jBz4ergY2ux1u",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"y1qxBTRSDNmRIZDSEXtwTP"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "state"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/html":[
       "<div><table style='border: 1px solid black;border-collapse: collapse;'><tr style='border: 1px solid black;border-collapse: collapse;'><td style='border: 1px solid black;border-collapse: collapse;'>X<\/td><td style='border: 1px solid black;border-collapse: collapse;'>‍<\/td><td style='border: 1px solid black;border-collapse: collapse;'>O<\/td><\/tr>\n",
       "<tr style='border: 1px solid black;border-collapse: collapse;'><td style='border: 1px solid black;border-collapse: collapse;'>‍<\/td><td style='border: 1px solid black;border-collapse: collapse;'>X<\/td><td style='border: 1px solid black;border-collapse: collapse;'>‍<\/td><\/tr>\n",
       "<tr style='border: 1px solid black;border-collapse: collapse;'><td style='border: 1px solid black;border-collapse: collapse;'>‍<\/td><td style='border: 1px solid black;border-collapse: collapse;'>‍<\/td><td style='border: 1px solid black;border-collapse: collapse;'>‍<\/td><\/tr><\/table><\/div>"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    },
    {
     "data":{
      "text\/plain":[
       "[[X, Empty, O], [Empty, X, Empty], [Empty, Empty, Empty]]"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"5PphdaFz14XBvovS6ZYF8z",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"HAMo4XcsvceFepwnsltw4q"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "The following renderer will render not to `DisplayResult`, but to a `BufferedImage`.\n",
    "Kernel knows how to render `BufferedImage`, that's because it works fine."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"Bu94DrZBzM5aNZzmNILMJl",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"qDjMyIfpi7x9tS6RQm0eqH"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "import java.awt.Color\n",
    "import java.awt.geom.Ellipse2D\n",
    "import java.awt.image.BufferedImage\n",
    "\n",
    "@OptIn(ExperimentalStdlibApi::class)\n",
    "val imageStateRenderer = createRenderer<TTTState> { state ->\n",
    "    val cellSize = 100\n",
    "    val padding = 5\n",
    "    val mtx = state.stateMatrix\n",
    "    val rowsCount = mtx.size\n",
    "    val colsCount = mtx.first().size\n",
    "    val width = 2 * padding + cellSize * colsCount\n",
    "    val height = 2 * padding + cellSize * rowsCount\n",
    "\n",
    "    val img = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)\n",
    "    val g = img.createGraphics()\n",
    "    g.color = Color.BLACK\n",
    "\n",
    "    val figPadding = cellSize \/ 10\n",
    "    fun drawCell(xOffset: Int, yOffset: Int, cell: TTTCell) {\n",
    "        when (cell) {\n",
    "            TTTCell.X -> {\n",
    "                g.drawLine(\n",
    "                    xOffset + figPadding,\n",
    "                    yOffset + figPadding,\n",
    "                    xOffset + cellSize - figPadding,\n",
    "                    yOffset + cellSize - figPadding\n",
    "                )\n",
    "                g.drawLine(\n",
    "                    xOffset + cellSize - figPadding,\n",
    "                    yOffset + figPadding,\n",
    "                    xOffset + figPadding,\n",
    "                    yOffset + cellSize - figPadding\n",
    "                )\n",
    "            }\n",
    "            TTTCell.O -> {\n",
    "                g.draw(Ellipse2D.Double(\n",
    "                    (xOffset + figPadding).toDouble(),\n",
    "                    (yOffset + figPadding).toDouble(),\n",
    "                    (cellSize - 2 * figPadding).toDouble(),\n",
    "                    (cellSize - 2 * figPadding).toDouble(),\n",
    "                ))\n",
    "            }\n",
    "\n",
    "            TTTCell.Empty -> {}\n",
    "        }\n",
    "    }\n",
    "\n",
    "    fun drawGrid() {\n",
    "        for (i in 0..rowsCount) {\n",
    "            g.drawLine(\n",
    "                padding,\n",
    "                padding + i * cellSize,\n",
    "                padding + colsCount * cellSize,\n",
    "                padding + i * cellSize,\n",
    "            )\n",
    "        }\n",
    "        for (j in 0..colsCount) {\n",
    "            g.drawLine(\n",
    "                padding + j * cellSize,\n",
    "                padding,\n",
    "                padding + j * cellSize,\n",
    "                padding + rowsCount * cellSize,\n",
    "            )\n",
    "        }\n",
    "    }\n",
    "\n",
    "    drawGrid()\n",
    "    for (i in 0..< rowsCount) {\n",
    "        for (j in 0..< colsCount) {\n",
    "            drawCell(padding + j * cellSize, padding + i * cellSize, mtx[i][j])\n",
    "        }\n",
    "    }\n",
    "\n",
    "    img\n",
    "}\n",
    "\n",
    "notebook.renderersProcessor.registerWithoutOptimizing(imageStateRenderer, ProcessingPriority.HIGHER)"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"m9mMXXKfygvqQT9Dy5t6VZ",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"Nd5ZojCHu4qwbynpIuulr9"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "state"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "image\/png":[
       "iVBORw0KGgoAAAANSUhEUgAAATYAAAE2CAYAAADrvL6pAAASDElEQVR4Xu3W0W7ltrZE0fz\/T9+LRk7DiWO3JymyWJLmAPZDkuLiEgsw8tdfkiRJkiRJkiRJwP\/58+fP341+CA4qwj662EcX3AcOKsI+uthHF9wHDirCPrrYRxfcBw4qwj662EcX3AcOKsI+uthHF9wHDirCPrrYRxfcBw4qwj662EcX3AcOKsI+uthHF9wHDirCPrrYRxfcBw3SnL5G34\/mlHHXPn7t\/affXeHdcfCvsaw+jLzbSFb7tffx+Q8W\/cP1OT9y9iS8Hw7+z2j+7UbfazSvvRr72P1HaPf8K\/BOOPgPM2feaOadZs5on5Y+Tv2xOXXvd\/AeOPjJ7Lm3mH2f2XPa43QfbX9UTu+C78fBL1w5+2RX3uXKWa13so+Td\/\/Jyb3w3Tj4javnn+bqe1w9r7VO9NHwf0Y\/ObUjvhMH\/2DFjCdY8Q4rZmidZB+n\/lhckd4Z34WDP1g1565Wff+qOVoj1Ufqnl1S++N7cBBYOetOVn73ylm6bncf6f\/j2SnxLXg+DkKr57Vb\/b2r5+manX3snH3Szu\/Cs3FwwI6ZjXZ8546Zmrerj11zW+z6PjwXBwftmtti1\/ftmqs5O\/rYMbPRju\/EM3Fwws7ZJ+38rp2zNW51H6vntVv9vXgeDk7aPT9t9\/fsnq8xK\/tYOetOVn43noWDFyTuSEh8R+IOcSv7WDnrTlZ+N56Fgxel7tkltX\/qHjGr+lg1565WfT+eg4MLJO9aKbl38i79bEUfK2Y8wYp3wDNwcJH0fVel903fpz9b0ceKGU+w4h3wDBxc6MSdM07seeJOfe9qH1fPP83V98DncXCxU\/dSp\/Y7da++drWPq+ef5up74PM4uMHJu\/\/k5F4n79Z\/Xenjytknu\/Iu+CwObnL6\/s9O73P6fv3bbB+z595i9n3wORzcqGGHXxr2aNhBH2b7mD33FrPvg8\/h4Gan9zh9\/28te+hvM33MnHmjmXfCZ3Aw4NQup+79StMumutj5swbzbwTPoODIel90vf9pG2ft5vpY+bMG828Ez6Dg0GpnVL3jGjc6c1G+xjNv93oe+E8Dobt3mv3\/Fmte73VaB+j+bcbfS+cx8EDdu22a+4Kzbu90Wgfo\/m3G30vnMfBQ1bvt3reau37vc1IHyNZfRh5N5zFwYNW7bhqzk532PFNRvoYyerDyLvhLA4ednXPq+dT7rLnW4z0MZLVh5F3w1kcLDC76+y5E+606xuM9DGS1YeRd8NZHCwxuu9o\/rS77ft0I32MZPVh5N1wFgeL0J1prskdd36ykT5Gsvow8m44i4Nlftr7p\/\/e6q57P9VIHyNZ\/Rt9O5rjwULf7f7dv7+DO+\/+RLQPmtPX6PvRHA+W+rz\/53++m7vv\/zS0D5rT1+j70RwPFvv9DU\/6FnWgfdCcvkbfj+Z4sJzfoR1oHzSnr9H3ozkeLOb\/sWkX2gfN6Wv0\/WiOB0t93v\/zP9\/N3fd\/GtoHzelr9P1ojgcLfbf7d\/\/+Du68+xPRPmhOX6PvR3M8WOanvX\/6763uuvdT0T5oTv818nY4i4NF6M401+SOOz\/ZSB8jWX0YeTecxcESo\/uO5k+7275PN9LHSFYfRt4NZ3GwwOyus+dOuNOubzDSx0hWH0beDWdx8LCre149n3KXPd9ipI+RrD6MvBvO4uBBq3ZcNWenO+z4JiN9jGT1YeTdcBYHD1m93+p5q7Xv9zYjfYxk9WHk3XAWBw\/YtduuuSs07\/ZGo32M5t9u9L1wHgfDdu+1e\/6s1r3earSP0fzbjb4XzuNgUGqn1D0jGnd6s9E+RvNvN\/peOI+DIel90vf9pG2ft5vpY+bMG828Ez6DgwGndjl171eadtFcHzNn3mjmnfAZHNzs9B6n7\/+tZQ\/9baaPmTNvNPNO+AwObtSwwy8NezTsoA+zfcyee4vZ98HncHCT0\/d\/dnqf0\/fr32b7mD33FrPvg8\/h4AYn7\/6Tk3udvFv\/daWPK2ef7Mq74LM4uNipe6lT+526V1+72sfV809z9T3weRxc6MSdM07seeJOfe9qH1fPP83V98DncXCR9H1XpfdN36c\/W9HHihlPsOId8AwcXCB510rJvZN36Wcr+lgx4wlWvAOegYMXpe7ZJbV\/6h4xq\/pYNeeuVn0\/noODFyTuSEh8R+IOcSv7WDnrTlZ+N56Fg5N2z0\/b\/T2752vMyj5WzrqTld+NZ+HghJ2zT9r5XTtna9zqPlbPa7f6e\/E8HBy0a26LXd+3a67m7Ohjx8xGO74Tz8TBATtmNtrxnTtmat6uPnbNbbHr+\/BcHIRWz2u3+ntXz9M1O\/vYOfuknd+FZ+MgsHLWnaz87pWzdN3uPn7N331HSuJb8Hwc\/MGqOXe16vtXzdEaqT5S9+yS2h\/fg4N\/sGLGE6x4hxUztE6yj8T\/8ayW3hnfhYPfuHr+aa6+x9XzWutEH+k\/FjNO7YjvxMEvXDn7ZFfe5cpZrXeyj5N3\/8nJvfDdOPjJ7Lm3mH2f2XPa43Qfp\/7P6CsNu+D7cfAfZs680cw7zZzRPi19\/P6jkt7n1L3fwXvg4P+M5t9u9L1G89qrsY\/df2x2z78C74SDf41l9WHk3Uay2q+9j3\/+Efr8+8nnPD13Et6PBmlOX6PvR3PKuHMfn\/9gff7dEd4bBxVhH13sowvuAwcVYR9d7KML7gMHFWEfXeyjC+4DBxVhH13sowvuAwcVYR9d7KML7gMHFWEfXeyjC+4DBxVhH13sowvuAwcVYR9d7KML7gMHFWEfXeyjC+7jV9CfP3\/+7vJDcFAR9tHFPrrgPnBQEfbRxT664D5wUBH20cU+uuA+cFAR9tHFPrrgPnBQEfbRxT664D5wUBH20cU+uuA+cFAR9tHFPrrgPnBQEfbRxT664D5wUBH20cU+uuA+cFARtA+a09fo+9GcMnAfOKiIkT5Gsvow8m4jWe2H+8BBRYz2MZp\/u9H3Gs1rL9wHDipipo+ZM280804zZ7QP7gMHFTHbx+y5t5h9n9lz2gP3gYOKuNLHlbNPduVdrpzVergPHFTE1T6unn+aq+9x9bzWwn3goCJW9LFixhOseIcVM7QO7gMHFbGqj1Vz7mrV96+aozVwHzioiJV9rJx1Jyu\/e+UsXYf7wEFFrO5j9bx2q7939Txdg\/vAQUXs6GPHzEY7vnPHTM3DfeCgInb1sWtui13ft2uu5uA+cFARO\/vYOfuknd+1c7bG4T5wUBG7+9g9P2339+yerzG4DxxURKKPxB0Jie9I3CEO94GDikj1kbpnl9T+qXvE4D5wUBHJPpJ3rZTcO3mXfob7wEFFpPtI33dVet\/0ffoz3AcOKuJEHyfunHFizxN36nu4DxxUxKk+Tt1Lndrv1L36Gu4DBxVxso+Td\/\/Jyb1O3q3\/wn3goCJO93H6\/s9O73P6fv0b7gMHFdHQR8MOvzTs0bCDPuA+cFARLX2c3uP0\/b+17KG\/4T5wUBFNfZza5dS9X2naRQN94KAi2vpI75O+7ydt+7wd7gMHFdHYR2qn1D0jGnd6M9wHDiqitY\/de+2eP6t1r7fCfeCgIpr72LXbrrkrNO\/2RrgPHFREex+r91s9b7X2\/d4G94GDirhDH6t2XDVnpzvs+Ca4DxxUxF36uLrn1fMpd9nzLXAfOKiIO\/Uxu+vsuRPutOsb4D5wUBF362N039H8aXfb9+lwHzioiDv2QXemuSZ33PnJcB84qIi79vHT3j\/991Z33fupcB84qIg79\/Hd7t\/9+zu48+5PhPvAQUXcvY\/P+3\/+57u5+\/5Pg\/vAQUU8oY\/f3\/Ckb1EH3AcOKuIpffgd2gH3gYOKeEIf\/h+bdsF94KAi7t7H5\/0\/\/\/Pd3H3\/p8F94KAi7tzHd7t\/9+\/v4M67PxHuAwcVcdc+ftr7p\/\/e6q57PxXuAwcVccc+6M401+SOOz8Z7gMHFXG3Pkb3Hc2fdrd9nw73gYOKuFMfs7vOnjvhTru+Ae4DBxVxlz6u7nn1fMpd9nwL3AcOKuIOfazacdWcne6w45vgPnBQEe19rN5v9bzV2vd7G9wHDiqiuY9du+2au0Lzbm+E+8BBRbT2sXuv3fNnte71VrgPHFREYx+pnVL3jGjc6c1wHzioiLY+0vuk7\/tJ2z5vh\/vAQUU09XFql1P3fqVpFw30gYOKaOnj9B6n7\/+tZQ\/9DfeBg4po6KNhh18a9mjYQR9wHzioiNN9nL7\/s9P7nL5f\/4b7wEFFnOzj5N1\/cnKvk3frv3AfOKiIU32cupc6td+pe\/U13AcOKuJEHyfunHFizxN36nu4DxxURLqP9H1XpfdN36c\/w33goCKSfSTvWim5d\/Iu\/Qz3gYOKSPWRumeX1P6pe8TgPnBQEYk+EnckJL4jcYc43AcOKmJ3H7vnp+3+nt3zNQb3gYOK2NnHztkn7fyunbM1DveBg4rY1ceuuS12fd+uuZqD+8BBRezoY8fMRju+c8dMzcN94KAiVvexel671d+7ep6uwX3goCJW9rFy1p2s\/O6Vs3Qd7gMHFbGqj1Vz7mrV96+aozVwHzioiBV9rJjxBCveYcUMrYP7wEFFXO3j6vmnufoeV89rLdwHDiriSh9Xzj7ZlXe5clbr4T5wUBGzfcyee4vZ95k9pz1wHzioiJk+Zs680cw7zZzRPrgPHFTEaB+j+bcbfa\/RvPbCfeCgIkb6GMnqw8i7jWS1H+4DBxVB+6A5fY2+H80pA\/eBg4qwjy720QX3gYOKsI8u9tEF94GDirCPLvbRBfeBg4qwjy720QX3gYOKsI8u9tEF94GDirCPLvbRBfeBg4qwjy720QX3gYOKsI8u9tEF94GDirCPLvbRBffxK+jPnz9\/d\/khOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfOKgI++hiH11wHzioCPvoYh9dcB84qAj76GIfXXAfv4L+\/Pnzd5efJEmSJEmSpIX+H8jrcygzyPgqAAAAAElFTkSuQmCC"
      ]
     },
     "metadata":{
      "image\/png":{
       
      }
     },
     "output_type":"display_data"
    },
    {
     "data":{
      "text\/plain":[
       "class java.awt.image.BufferedImage: 310x310 px"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"kwGhJrChXIRY0tYqmotHfc",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"4hEPWmIcECUaChEgXJrN0S"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "Renderer for `BufferedImage` is already registered!"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"ng2zV101bxX24o7MSgD6dZ",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"Qd052RbLjMEDY3x2JGGqTv"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    render<TTTState> { it }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"sQjhort3iyyWDrLl9AtNFg",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"MBhVi2ZZKdBe0dT3idTCsR"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.renderersProcessor.registeredRenderers()\n",
    "    .map { it.renderer }\n",
    "    .filter { (it as? RendererTypeHandler)?.acceptsType(BufferedImage::class) == true }"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "[Renderer of subtypes of class java.awt.image.BufferedImage]"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"84VYitLbQDrzppAY3kkMVM",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"X5HduZd3JUswZqdIvQWcvr"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "You can add a renderer in the library descriptor as well, but functionality isn't\n",
    "so rich there. In fact, you can only write code-based renderers, and renderers are\n",
    "matched by **exact** FQN match. Subtypes aren't accepted."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"neNhsh456vZpwFtqBB3eCG",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"9nzoHcpCP1GLrQWAukO1fW"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val dollar = \"$\"\n",
    "val dollarIt = \"\\$it\"\n",
    "\n",
    "class Customer2(val name: String, val age: Int)\n",
    "\n",
    "loadLibraryDescriptor(\n",
    "    \"\"\"\n",
    "        {\n",
    "            \"renderers\": {\n",
    "                \"${Customer2::class.qualifiedName}\": \"\\\"Customer $dollar{${dollarIt}.name} aged $dollar{${dollarIt}.age}\\\"\"\n",
    "            }\n",
    "        }\n",
    "    \"\"\"\n",
    ")"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"DjeeRi7xI6DAN675VH3TV9",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"ffdXcOShKpmT2VFamXtJoC"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "Customer2(\"Ada\", 42)"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "Customer Ada aged 42"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"YKWpaYM2PmmUpoF9vhf61N",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"kHqcBGP4zD4qWEOevgWkNs"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "One more thing that you can render are exceptions! Let's add a renderer for `NullPointerException`"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"JvvYOG9AwfJmiLrbi9ptjh",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"gdPUAVfcoA8aRXf03ir1fe"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    renderThrowable<NullPointerException> {\n",
    "        HTML(\"<b>Kotlin is a null-safe language<\/b>\")\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"0bmnxaUAEOgc3cJDuZ2Lc2",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"82XbePaUlOwT2VXGYcd3i1"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "System.getProperty(\"some_unexistent_property\")!!"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/html":[
       "<b>Kotlin is a null-safe language<\/b>"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"25RWEOniQuibHNAUEFrZGX",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"4V66M4w1UlwOuLZ5IY81NX"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "You can also render having current execution host in the context"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"DdO4dw40LFzJt0TlKDs7Ne",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"fYC5xnKtUSpYiFLT4HkPws"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    fun TTTCell.toHTML() = HTML(\"<TODO>\")\n",
    "\n",
    "    renderWithHost<TTTCell> { executionHost, value ->\n",
    "        executionHost.execute {\n",
    "            display(value.toHTML(), \"12\")\n",
    "            display(textResult(value.toString()), \"\")\n",
    "        }\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"4UpYgouDImsXkRAmaOLt7w",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"kuzi0a4lenTKR7ytAIYZmk"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Code preprocessing\n",
    "\n",
    "Kotlin kernel gives you an ability to preprocess the code before execution.\n",
    "One of the examples of preprocessing is magics. They are preprocessed with a built-in processor.\n",
    "But sometimes you have to write your own one.\n",
    "\n",
    "For now, you can't run suspend functions directly in the notebook cells. Let's\n",
    "try to improve the situation writing a workaround for this problem. We start\n",
    "with creating a function"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"wuFD1A0TnFq8qZ6IPoYLIa",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"NOfKq0qMhXm4RcKXXqyYwo"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "%use coroutines"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"58W81fgX6daM7aIKDnnavh",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"dDJZFeeBhojcOcn3fSLEN9"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "private class Decl(val varMod: String, val name: String)\n",
    "\n",
    "fun generateRunBlocking(code: String): String {\n",
    "    val declarationRegex = \"\"\"^(va[lr]) +(\\w+) \"\"\".toRegex(RegexOption.MULTILINE)\n",
    "    val matches = declarationRegex.findAll(code).toList()\n",
    "    val newCode = code.toCharArray()\n",
    "    val declarations = matches.map { m ->\n",
    "        val modGroup = m.groups[1]!!\n",
    "        val modifier = modGroup.value\n",
    "        for (i in modGroup.range) {\n",
    "            newCode[i] = ' '\n",
    "        }\n",
    "        val varName = m.groups[2]!!.value\n",
    "        Decl(modifier, varName)\n",
    "    }\n",
    "    return buildString {\n",
    "        for (decl in declarations) {\n",
    "            append(\"var ${decl.name}: Any? = null\\n\")\n",
    "        }\n",
    "        append(\"runBlocking {\\n\")\n",
    "        append(String(newCode))\n",
    "        append(\"\\n}\")\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"xhyJl9glfo6cA260XrKLDh",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"rmLFvTENMlhrdGdMmhlyIY"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "Let's test it"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"SiixTH7FAskvuw87Lfd3lt",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"pkdocjfEgkHGZkNZEg0qCd"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "generateRunBlocking(\"\"\"\n",
    "    val xyz = 42\n",
    "    var t = 12\n",
    "\"\"\".trimIndent())"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "var xyz: Any? = null\n",
       "var t: Any? = null\n",
       "runBlocking {\n",
       "    xyz = 42\n",
       "    t = 12\n",
       "}"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"rZWCos0jH1pOtVldRGKTLd",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"2L3O1gtgQ8JkbcyvVkKWfr"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    preprocessCode { code -> generateRunBlocking(code) }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"ufBXDa1Z2D1lqqzsC5jsx1",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"pOyf1UlbzzgBt6BrEgyP7E"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "suspend fun susF(): Int = 42\n",
    "\n",
    "val a = susF()"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"2XzF3wRX6NlEi908xxy79f",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"96w8EcjnewffqtxVvAuwxe"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "a"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "42"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"YrKPSd2rYaSdmMqCqg3wpZ",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"kIaSOBKE2g3ETEsImhWpdg"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val processors = notebook.codePreprocessorsProcessor.registeredExtensions().toList()\n",
    "println(processors)"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "[org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration$Builder$preprocessCodeWithLibraries$1@599b664e, org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor@6b1106a5]\r\n"
     ],
     "output_type":"stream"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"ZSwIBjnKNC9wUbR77I809V",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"llihElBjAad2oVi7hWmWAx"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.codePreprocessorsProcessor.unregister((processors!! as List<CodePreprocessor>)[0])"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"lCcIkGEmDmPrV08sm0QPyQ",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"l6bMEDM7mmkgLAYM3Cx11y"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val processors2 = notebook.codePreprocessorsProcessor.registeredExtensions().toList()\n",
    "println(processors2)"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "[org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor@6b1106a5]\r\n"
     ],
     "output_type":"stream"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"NsralVlhrNcMb9qo6aYVoD",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"uMUYx3GxM8W3gSyXYyndH7"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Reflection- and compile-based postprocessing"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"Yuom2vfRznicODzeNz2iWH",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"uA1w1Ni8u1amC6sqba2deq"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "As we discussed above, there is possibility to add after-evaluation callbacks.\n",
    "There is a possibility to consider script instance as well. Script instance\n",
    "contains all top-level variables and functions you define as members. Let's take a look"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"fI6J2geUPju5oQkqKb6UJL",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"UQMvJcHI0ln68VZJIE06He"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "import kotlin.reflect.KProperty\n",
    "import kotlin.reflect.KProperty1\n",
    "import kotlin.reflect.full.memberFunctions\n",
    "import kotlin.reflect.full.memberProperties\n",
    "\n",
    "USE {\n",
    "    afterCellExecution { snippetInstance, _ ->\n",
    "        val kClass = snippetInstance::class\n",
    "        println(\n",
    "            \"\"\"\n",
    "Variables:\n",
    "${\n",
    "    kClass.memberProperties.joinToString(\"\\n\") { prop ->\n",
    "        \"${prop.name} = ${\n",
    "            (prop as KProperty1<Any, Any?>).get(\n",
    "                snippetInstance\n",
    "            )\n",
    "        }\"\n",
    "    }\n",
    "}\n",
    "\n",
    "Functions:\n",
    "${kClass.memberFunctions.joinToString(\"\\n\") { f -> f.name }}\n",
    "        \"\"\"\n",
    "        )\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"cuf7gLKdl8bK8RhWcRP5JX",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"JIR4tHKUJupbyHezxDu6rB"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val myVar1 = 42\n",
    "val myVar2 = \"str\"\n",
    "\n",
    "fun myFun1() { println(\"fun called\") }"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "\n",
      "Variables:\n",
      "myVar1 = 42\n",
      "myVar2 = str\n",
      "userHandlesProvider = org.jetbrains.kotlinx.jupyter.ReplForJupyterImpl@4d7b2340\n",
      "\n",
      "Functions:\n",
      "myFun1\n",
      "equals\n",
      "hashCode\n",
      "toString\n",
      "        \r\n"
     ],
     "output_type":"stream"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"fwCdP3B5jvwkKrMOew4DbM",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"NvyjPbw6vlV9DWit5NXRvi"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.afterCellExecutionsProcessor.unregisterAll()"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"Rdv5QgxSWWOGEYOw56HZ3H",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"DMUBf9e38abIudGGGHZrk4"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "Let's now try to do something compile-time based. We start with file annotations processing"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"Iw3cA7GOJzTSMejCwXURkk",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"Ue3t61m1qFdbl9fwdraTDd"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    onFileAnnotation<Suppress> {\n",
    "        val myAnno = it.first() as Suppress\n",
    "        println(\"Warnings suppressed: \" + myAnno.names.toList())\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"5OjDKIR999WfJF08kVA86Y",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"ftKvOUhM7UYCFRG8iznQP0"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "@file:Suppress(\"UNUSED_PARAMETER\")\n",
    "\n",
    "fun u(unusedArg: Int) = 44"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "Warnings suppressed: [UNUSED_PARAMETER]\r\n"
     ],
     "output_type":"stream"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"Nh3EpmYl0tBAxGwwqwXQNB",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"unVxCJ8mv1nzlS9snliOpW"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "We can also handle annotations for classes. They are runtime-based."
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"sANMnKtdLBqWHE0UY4khwY",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"7oBfufAnaB25PwW9IheO4A"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "annotation class MyAnnotation"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"fPWAxrOHL7h1vqTLkbapvJ",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"ZgdMbkYUbDk204pfAfvdSz"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    onClassAnnotation<MyAnnotation> { println(\"Annotated classes: $it\") }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"zKc6ZM3mWDVbaZDBzRv58R",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"NylSfpzWwx01t38GW0vXGS"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "@MyAnnotation\n",
    "class MyClass\n",
    "\n",
    "class MyClass2\n",
    "\n",
    "@MyAnnotation\n",
    "interface MyInterface3\n",
    "\n",
    "3 + 3"
   ],
   "execution_count":null,
   "outputs":[
    {
     "name":"stdout",
     "text":[
      "Annotated classes: [class Line_83_jupyter$MyClass, class Line_83_jupyter$MyInterface3]\r\n",
      "\n"
     ],
     "output_type":"stream"
    },
    {
     "name":"stderr",
     "text":[
      "\n"
     ],
     "output_type":"stream"
    },
    {
     "data":{
      "text\/plain":[
       "6"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"iIk33g296Bt6B27UvrTDyz",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"Eq0K2et7uGLQlKSnAWm8Uq"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "class MyData\n",
    "\n",
    "USE {\n",
    "    onVariable<MyData> { t, kProperty ->\n",
    "        execute(\"val gen_${kProperty.name} = 1\")\n",
    "    }\n",
    "\/\/    updateVariable<MyData> { t, kProperty ->\n",
    "\/\/        execute(\"\")\n",
    "\/\/\n",
    "\/\/    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"5VdHBYcZNscUy0ou5yUMKt",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"eaAFdDYc1oCRRGDgPy8AGJ"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val d = MyData()"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"MgfPiwZIKmWInsmZlCnsHI",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"soaq6Yi9OYf8mQbpJRCb7j"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "gen_d"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "1"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"QK41I4Epmue1zjnyHgICo8",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"kBanpx6Ot83NVP52jes2xZ"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Variables reports"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"8CNMoO5jhodouuWOJYRJBP",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"mptCNNSClB79mlxA6WYEe4"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.variablesReport"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "Visible vars: \n",
       "\tdollar : $\n",
       "\treadToken : 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\n",
       "\tmyVar1 : 42\n",
       "\tconfig1 : Line_16_jupyter$Config@45d5ee1e\n",
       "\tmyVar3 : Line_16_jupyter$Config@45d5ee1e\n",
       "\tinterruptionCount : 1\n",
       "\tisDark : false\n",
       "\tgameState : x_o|_x_|___\n",
       "\tstateMatrix : [[X, Empty, O], [Empty, X, Empty], [Empty, Empty, Empty]]\n",
       "\tstate : Line_47_jupyter$TTTState@1f8e46f4\n",
       "\thtmlStateRenderer : Renderer of subtypes of class Line_47_jupyter$TTTState\n",
       "\timageStateRenderer : Renderer of subtypes of class Line_47_jupyter$TTTState\n",
       "\tdollarIt : $it\n",
       "\t___a : 42\n",
       "\ta : 42\n",
       "\t___processors : [org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration$Builder$preprocessCodeWithLibraries$1@599b664e, org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor@6b1106a5]\n",
       "\tprocessors : [org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration$Builder$preprocessCodeWithLibraries$1@599b664e, org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor@6b1106a5]\n",
       "\tprocessors2 : [org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor@6b1106a5]\n",
       "\tmyVar2 : str\n",
       "\td : Line_84_jupyter$MyData@9b17514\n",
       "\tgen_d : 1\n"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"5ahvq3kILgZ4xr0Jt8UZUV",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"g97VskGuaBU5jyi2xxOJUb"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    markVariableInternal { prop ->\n",
    "        prop.name.startsWith(\"___\")\n",
    "    }\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"fLOUvAhGCF8NRHi1PWmTBe",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"Fes2WbRkwHV6Du6NNpNfN8"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "val ___b = 8\n",
    "val b = 9"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"KoOWWoR61ZGylladTKqlt5",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"9FJyAOc7qD5ZKKsxhS2plB"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "notebook.variablesReport"
   ],
   "execution_count":null,
   "outputs":[
    {
     "data":{
      "text\/plain":[
       "Visible vars: \n",
       "\tdollar : $\n",
       "\treadToken : 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\n",
       "\tmyVar1 : 42\n",
       "\tconfig1 : Line_16_jupyter$Config@45d5ee1e\n",
       "\tmyVar3 : Line_16_jupyter$Config@45d5ee1e\n",
       "\tinterruptionCount : 1\n",
       "\tisDark : false\n",
       "\tgameState : x_o|_x_|___\n",
       "\tstateMatrix : [[X, Empty, O], [Empty, X, Empty], [Empty, Empty, Empty]]\n",
       "\tstate : Line_47_jupyter$TTTState@1f8e46f4\n",
       "\thtmlStateRenderer : Renderer of subtypes of class Line_47_jupyter$TTTState\n",
       "\timageStateRenderer : Renderer of subtypes of class Line_47_jupyter$TTTState\n",
       "\tdollarIt : $it\n",
       "\t___a : 42\n",
       "\ta : 42\n",
       "\t___processors : [org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration$Builder$preprocessCodeWithLibraries$1@599b664e, org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor@6b1106a5]\n",
       "\tprocessors : [org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration$Builder$preprocessCodeWithLibraries$1@599b664e, org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor@6b1106a5]\n",
       "\tprocessors2 : [org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor@6b1106a5]\n",
       "\tmyVar2 : str\n",
       "\td : Line_84_jupyter$MyData@9b17514\n",
       "\tgen_d : 1\n",
       "\tb : 9\n"
      ]
     },
     "metadata":{
      
     },
     "output_type":"display_data"
    }
   ],
   "metadata":{
    "datalore":{
     "node_id":"Se41f1KLqwakQF9AeTOsr7",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"dEtLSwVj8RQQMjcZQlsPhB"
     }
    }
   }
  },
  {
   "cell_type":"markdown",
   "source":[
    "## Auxiliary"
   ],
   "attachments":{
    
   },
   "metadata":{
    "datalore":{
     "node_id":"noC2jHXlVoQ3PMfuElXPoG",
     "type":"MD",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"9a8AAkac3yjxfQQJywjA8z"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "\/\/ You can set minimal supported version of kernel\n",
    "USE {\n",
    "    setMinimalKernelVersion(\"0.11.0.365\")\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"gyyNLLGMnX9FzdAXqkW1uA",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"bK2uTOWSiI8RG4NCcZz9LY"
     }
    }
   }
  },
  {
   "cell_type":"code",
   "source":[
    "USE {\n",
    "    setDescription(\"Very good library\")\n",
    "    setWebsite(\"https:\/\/cool.site\")\n",
    "}"
   ],
   "execution_count":null,
   "outputs":[
    
   ],
   "metadata":{
    "datalore":{
     "node_id":"TN8rb2Cg0tKiEYhimMLvhV",
     "type":"CODE",
     "hide_input_from_viewers":false,
     "hide_output_from_viewers":false,
     "report_properties":{
      "rowId":"PiIX4Cd5LWPealJqQT75s7"
     }
    }
   }
  }
 ],
 "metadata":{
  "kernelspec":{
   "display_name":"Kotlin",
   "language":"kotlin",
   "name":"kotlin"
  },
  "datalore":{
   "computation_mode":"JUPYTER",
   "package_manager":"pip",
   "base_environment":"default",
   "packages":[
    {
     "name":"kotlin-jupyter-kernel",
     "version":"0.11.0.365",
     "source":"PIP"
    }
   ],
   "report_row_ids":[
    "0ON8yI917hwj8FeK0pQsky",
    "vS92wiTvpFntHSEMCrr5H9",
    "3XSS7u0TNIQpjxsTLZoRig",
    "9aQzeJN8aSKkrM8z1a8Acs",
    "XiD8FUF2KgFyi8XBVKQpnU",
    "guaD3yArd3wnoMlMhxLe4X",
    "iUfleWm1l7UrnMboME6qdN",
    "SZQ4DmXm4LKPZXSWKa2FUa",
    "SqdpEchM5GWiblQZFplRpl",
    "YrLfbBZxK3gmzAjhOcToTI",
    "aY56fUvdq8nKDNJRhibmjc",
    "cM7Eec2U1CVBlHSH17Rg1D",
    "c3ukpEDkef9NnK5W6m80fX",
    "bJriUMfF1ALMgCZRqL2vPR",
    "eg2gxPucspll8gUsgPMeml",
    "WOxFiL3cGnwp0EfdM7ZMHv",
    "PwhJpKfF01V5FgWZ0vKmJH",
    "ajiBPydxHG4Xeq9tlTUVNm",
    "trd9FQC5p4kj2twt1NSdZi",
    "ytCzH78nG3CehElCoOlCp2",
    "kIehA33S1UmxSoILQBOezz",
    "loTaywakOhZgSG9nNxroBD",
    "aRiAfUct8tkDWLUoCXSPUa",
    "29gNY5AfVcwwJIu9XdIeZC",
    "qPr8FSa9A021OrxQcpqgvf",
    "5H8VGC7gJEfYKSDQ1wDrFw",
    "LEj97CaHd6FEIUoWTDWrUd",
    "kUqpFEoT4wdrCyvaRjlL9U",
    "83T4EixM904negk4PspoX9",
    "jiBee7WXAMh0dRE0mXCwYJ",
    "vWW1rKGiTC5wCiRppqSPtl",
    "NZYYw8krWxxsn6ViFn8HQZ",
    "dr2BNXz8zjk4Heei7SHzTo",
    "HLOTmBX4YcaBXoCInGaWBA",
    "sZDxeSOclpqLQU6I3U4ZFU",
    "XJdz2W54VQ71MD37E7zK44",
    "sWNQSLVUcaeEBmAPpke16g",
    "9uUmhY5IEWb0F9Z4LLL9ns",
    "9aUzTpm3Fs3zjX6Fl5svDH",
    "XKeLbzujSGyt7sGXweJGW6",
    "TjL2Gby4DlurAmXZNsOMiY",
    "FSrS8i1Hfq5tw0NeYR13tC",
    "wCZCvAr5I4GqhHJUWcEKSL",
    "8RvJheV7qmMV3TgAjrClo9",
    "cZG2Gg1q6ricyrJ2obqEVN",
    "MgHGwgpl2ke1SqG0BvCeuI",
    "CKP7bVtnKhgS7hYqLrbKIs",
    "FYVprXZJX8ybIkUdRYlbMC",
    "3CkWbCch8Jhw0YWvzybrWe",
    "yO7NShs20PgUXH62mQECW9",
    "ueDFLSiaxErv3sQNrMRxQK",
    "Zfx5UVcbiQybfkOTQunf2u",
    "mEXNvt604KWPfHBDZf3wLy",
    "uP4CXk9t9NAos3ns4xyVrl",
    "XsGdpQCPHSyqtXVbcGgYN4",
    "pHiR3R2hbskzidNu8lLsT0",
    "y1qxBTRSDNmRIZDSEXtwTP",
    "HAMo4XcsvceFepwnsltw4q",
    "qDjMyIfpi7x9tS6RQm0eqH",
    "Nd5ZojCHu4qwbynpIuulr9",
    "4hEPWmIcECUaChEgXJrN0S",
    "Qd052RbLjMEDY3x2JGGqTv",
    "MBhVi2ZZKdBe0dT3idTCsR",
    "X5HduZd3JUswZqdIvQWcvr",
    "9nzoHcpCP1GLrQWAukO1fW",
    "ffdXcOShKpmT2VFamXtJoC",
    "kHqcBGP4zD4qWEOevgWkNs",
    "gdPUAVfcoA8aRXf03ir1fe",
    "82XbePaUlOwT2VXGYcd3i1",
    "4V66M4w1UlwOuLZ5IY81NX",
    "fYC5xnKtUSpYiFLT4HkPws",
    "kuzi0a4lenTKR7ytAIYZmk",
    "NOfKq0qMhXm4RcKXXqyYwo",
    "dDJZFeeBhojcOcn3fSLEN9",
    "rmLFvTENMlhrdGdMmhlyIY",
    "pkdocjfEgkHGZkNZEg0qCd",
    "2L3O1gtgQ8JkbcyvVkKWfr",
    "pOyf1UlbzzgBt6BrEgyP7E",
    "96w8EcjnewffqtxVvAuwxe",
    "kIaSOBKE2g3ETEsImhWpdg",
    "llihElBjAad2oVi7hWmWAx",
    "l6bMEDM7mmkgLAYM3Cx11y",
    "uMUYx3GxM8W3gSyXYyndH7",
    "uA1w1Ni8u1amC6sqba2deq",
    "UQMvJcHI0ln68VZJIE06He",
    "JIR4tHKUJupbyHezxDu6rB",
    "NvyjPbw6vlV9DWit5NXRvi",
    "DMUBf9e38abIudGGGHZrk4",
    "Ue3t61m1qFdbl9fwdraTDd",
    "ftKvOUhM7UYCFRG8iznQP0",
    "unVxCJ8mv1nzlS9snliOpW",
    "7oBfufAnaB25PwW9IheO4A",
    "ZgdMbkYUbDk204pfAfvdSz",
    "NylSfpzWwx01t38GW0vXGS",
    "Eq0K2et7uGLQlKSnAWm8Uq",
    "eaAFdDYc1oCRRGDgPy8AGJ",
    "soaq6Yi9OYf8mQbpJRCb7j",
    "kBanpx6Ot83NVP52jes2xZ",
    "mptCNNSClB79mlxA6WYEe4",
    "g97VskGuaBU5jyi2xxOJUb",
    "Fes2WbRkwHV6Du6NNpNfN8",
    "9FJyAOc7qD5ZKKsxhS2plB",
    "dEtLSwVj8RQQMjcZQlsPhB",
    "9a8AAkac3yjxfQQJywjA8z",
    "bK2uTOWSiI8RG4NCcZz9LY",
    "PiIX4Cd5LWPealJqQT75s7"
   ],
   "version":3
  }
 },
 "nbformat":4,
 "nbformat_minor":4
}